--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Node / ReticulumProjects / Sideband.git / files / sbapp / plyer / platforms / android / filechooser.py
Displaying Raw • Download
sbapp/plyer/platforms/android/filechooser.py 2.0.0 (cf698d96) Text, 17.34 KB
T8b949e'''
Android file chooser
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Android runs ``Activity`` asynchronously via pausing our ``PythonActivity``
and starting a new one in the foreground. This means
``AndroidFileChooser._open_file()`` will always return the default value of
``AndroidFileChooser.selection`` i.e. ``None``.
After the ``Activity`` (for us it's the file chooser ``Intent``) is completed,
Android moves it to the background (or destroys or whatever is implemented)
and pushes ``PythonActivity`` to the foreground.
We have a custom listener for ``android.app.Activity.onActivityResult()``
via `android` package from `python-for-android` recipe,
``AndroidFileChooser._on_activity_result()`` which is called independently of
any our action (we may call anything from our application in Python and this
handler will be called nevertheless on each ``android.app.Activity`` result
in the system).
In the handler we check if the ``request_code`` matches the code passed to the
``Context.startActivityForResult()`` i.e. if the result from
``android.app.Activity`` is indeed meant for our ``PythonActivity`` and then we
proceed.
Since the ``android.app.Activity.onActivityResult()`` is the only way for us
to intercept the result and we have a handler bound via ``android`` package,
we need to get the path/file/... selection to the user the same way.
Threading + ``Thread.join()`` or ``time.sleep()`` or any other kind of waiting
for the result is not an option because:
1) ``android.app.Activity.onActivityResult()`` might remain unexecuted if
the launched file chooser activity does not return the result (``Activity``
dies/freezes/etc).
2) Thread will be still waiting for the result e.g. an update of a value or
to actually finish, however the result from the call of
``AndroidFileChooser._open_file()`` will be returned nevertheless and anything
using that result will use an incorrect one i.e. the default value of
``AndroidFilechooser.selection`` (``None``).
.. versionadded:: 1.4.0
'''
Tff7b72from T7ee787osT7ee787.T7ee787path Tff7b72import Te6edf3join
Tff7b72from T7ee787random Tff7b72import Te6edf3randint
Tff7b72from T7ee787android Tff7b72import Te6edf3activityTb4b4b4, Te6edf3mActivity
Tff7b72from T7ee787jnius Tff7b72import Te6edf3autoclassTb4b4b4, Te6edf3castTb4b4b4, Te6edf3JavaException
Tff7b72from T7ee787plyerT7ee787.T7ee787facades Tff7b72import Te6edf3FileChooser
Tff7b72from T7ee787plyer Tff7b72import Te6edf3storagepath
Te6edf3Environment Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff"Ta5d6ffandroid.os.EnvironmentTa5d6ff"Tb4b4b4)
Te6edf3String Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffjava.lang.StringTa5d6ff'Tb4b4b4)
Te6edf3Intent Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.content.IntentTa5d6ff'Tb4b4b4)
Te6edf3Activity Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.app.ActivityTa5d6ff'Tb4b4b4)
Te6edf3DocumentsContract Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.provider.DocumentsContractTa5d6ff'Tb4b4b4)
Te6edf3ContentUris Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.content.ContentUrisTa5d6ff'Tb4b4b4)
Te6edf3Uri Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.net.UriTa5d6ff'Tb4b4b4)
Te6edf3Long Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffjava.lang.LongTa5d6ff'Tb4b4b4)
Te6edf3IMedia Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.provider.MediaStore$Images$MediaTa5d6ff'Tb4b4b4)
Te6edf3VMedia Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.provider.MediaStore$Video$MediaTa5d6ff'Tb4b4b4)
Te6edf3AMedia Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.provider.MediaStore$Audio$MediaTa5d6ff'Tb4b4b4)
Te6edf3Files Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffandroid.provider.MediaStore$FilesTa5d6ff'Tb4b4b4)
Te6edf3FileOutputStream Tff7b72= Te6edf3autoclassTb4b4b4(Ta5d6ff'Ta5d6ffjava.io.FileOutputStreamTa5d6ff'Tb4b4b4)
Tff7b72class T56d364AndroidFileChooserTb4b4b4(Te6edf3FileChooserTb4b4b4)Tb4b4b4:
T8b949e'''
FileChooser implementation for Android using
the built-in file browser via Intent.
.. versionadded:: 1.4.0
'''
T8b949e# filechooser activity <-> result pair identification
Te6edf3select_code Tff7b72= Tff7b72None
Te6edf3save_code Tff7b72= Tff7b72None
T8b949e# default selection value
Te6edf3selection Tff7b72= Tff7b72None
T8b949e# select multiple files
Te6edf3multiple Tff7b72= Tff7b72False
T8b949e# mime types
Te6edf3mime_type Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdocTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/mswordTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdocxTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.openxmlformats-officedocument.Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffwordprocessingml.documentTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffpptTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.ms-powerpointTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffpptxTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.openxmlformats-officedocument.Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffpresentationml.presentationTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffxlsTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.ms-excelTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffxlsxTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.openxmlformats-officedocument.Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffspreadsheetml.sheetTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fftextTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fftext/*Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffpdfTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/pdfTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffzipTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/zipTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffimageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffimage/*Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffvideoTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffvideo/*Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffaudioTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaudio/*Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffapplicationTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/*Ta5d6ff"Tb4b4b4}
Te6edf3selected_mime_type Tff7b72= Tff7b72None
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Tff7b72*Te6edf3argsTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tff7b72*Te6edf3argsTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffselect_code Tff7b72= Te6edf3randintTb4b4b4(T79c0ff123456Tb4b4b4, T79c0ff654321Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffsave_code Tff7b72= Te6edf3randintTb4b4b4(T79c0ff123456Tb4b4b4, T79c0ff654321Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffselection Tff7b72= Tff7b72None
T8b949e# bind a function for a response from filechooser activity
Te6edf3activityTff7b72.Td2a8ffbindTb4b4b4(Te6edf3on_activity_resultTff7b72=Tff7b72selfTff7b72.Td2a8ff_on_activity_resultTb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_handle_selectionTb4b4b4(Te6edf3selectionTb4b4b4)Tb4b4b4:
T8b949e'''
Dummy placeholder for returning selection from
``android.app.Activity.onActivityResult()``.
.. versionadded:: 1.4.0
'''
Tff7b72return Te6edf3selection
Tff7b72def Td2a8ff_open_fileTb4b4b4(Tff7b72selfTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)Tb4b4b4:
T8b949e'''
Running Android Activity is non-blocking and the only call
that blocks is onActivityResult running in GUI thread
.. versionadded:: 1.4.0
'''
T8b949e# set up selection handler
T8b949e# startActivityForResult is async
T8b949e# onActivityResult is sync
Tff7b72selfTff7b72.Td2a8ff_handle_selection Tff7b72= Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(
Ta5d6ff'Ta5d6ffon_selectionTa5d6ff'Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_handle_selection
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffselected_mime_type Tff7b72= \
Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6fffiltersTa5d6ff"Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4] Tff7b72if Ta5d6ff"Ta5d6fffiltersTa5d6ff" Tff7b72in Te6edf3kwargs Tff7b72else Ta5d6ff"Ta5d6ff"
T8b949e# create Intent for opening
Te6edf3file_intent Tff7b72= Te6edf3IntentTb4b4b4(Te6edf3IntentTff7b72.Td2a8ffACTION_GET_CONTENTTb4b4b4)
Tff7b72if Tb4b4b4(
Tff7b72not Tff7b72selfTff7b72.Td2a8ffselected_mime_type
Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Tff7b72selfTff7b72.Td2a8ffselected_mime_typeTb4b4b4, Tffa657strTb4b4b4)
Tff7b72or Tff7b72selfTff7b72.Td2a8ffselected_mime_type Tff7b72not Tff7b72in Tff7b72selfTff7b72.Td2a8ffmime_type
Tb4b4b4)Tb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffsetTypeTb4b4b4(Ta5d6ff"Ta5d6ff*/*Ta5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffsetTypeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmime_typeTb4b4b4[Tff7b72selfTff7b72.Td2a8ffselected_mime_typeTb4b4b4]Tb4b4b4)
Te6edf3file_intentTff7b72.Td2a8ffaddCategoryTb4b4b4(
Te6edf3IntentTff7b72.Td2a8ffCATEGORY_OPENABLE
Tb4b4b4)
T8b949e# use putExtra to allow multiple file selection
Tff7b72if Te6edf3kwargsTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff'Ta5d6ffmultipleTa5d6ff'Tb4b4b4, Tff7b72selfTff7b72.Td2a8ffmultipleTb4b4b4)Tb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffputExtraTb4b4b4(Te6edf3IntentTff7b72.Td2a8ffEXTRA_ALLOW_MULTIPLETb4b4b4, Tff7b72TrueTb4b4b4)
T8b949e# start a new activity from PythonActivity
T8b949e# which creates a filechooser via intent
Te6edf3mActivityTff7b72.Td2a8ffstartActivityForResultTb4b4b4(
Te6edf3IntentTff7b72.Td2a8ffcreateChooserTb4b4b4(Te6edf3file_intentTb4b4b4, Te6edf3castTb4b4b4(
Ta5d6ff'Ta5d6ffjava.lang.CharSequenceTa5d6ff'Tb4b4b4,
Te6edf3StringTb4b4b4(Ta5d6ff"Ta5d6ffFileChooserTa5d6ff"Tb4b4b4)
Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffselect_code
Tb4b4b4)
Tff7b72def Td2a8ff_save_fileTb4b4b4(Tff7b72selfTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_save_callback Tff7b72= Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffcallbackTa5d6ff"Tb4b4b4)
Te6edf3title Tff7b72= Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffselected_mime_type Tff7b72= \
Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6fffiltersTa5d6ff"Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4] Tff7b72if Ta5d6ff"Ta5d6fffiltersTa5d6ff" Tff7b72in Te6edf3kwargs Tff7b72else Ta5d6ff"Ta5d6ff"
Te6edf3file_intent Tff7b72= Te6edf3IntentTb4b4b4(Te6edf3IntentTff7b72.Td2a8ffACTION_CREATE_DOCUMENTTb4b4b4)
Tff7b72if Tb4b4b4(
Tff7b72not Tff7b72selfTff7b72.Td2a8ffselected_mime_type
Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Tff7b72selfTff7b72.Td2a8ffselected_mime_typeTb4b4b4, Tffa657strTb4b4b4)
Tff7b72or Tff7b72selfTff7b72.Td2a8ffselected_mime_type Tff7b72not Tff7b72in Tff7b72selfTff7b72.Td2a8ffmime_type
Tb4b4b4)Tb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffsetTypeTb4b4b4(Ta5d6ff"Ta5d6ff*/*Ta5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffsetTypeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmime_typeTb4b4b4[Tff7b72selfTff7b72.Td2a8ffselected_mime_typeTb4b4b4]Tb4b4b4)
Te6edf3file_intentTff7b72.Td2a8ffaddCategoryTb4b4b4(
Te6edf3IntentTff7b72.Td2a8ffCATEGORY_OPENABLE
Tb4b4b4)
Tff7b72if Te6edf3titleTb4b4b4:
Te6edf3file_intentTff7b72.Td2a8ffputExtraTb4b4b4(Te6edf3IntentTff7b72.Td2a8ffEXTRA_TITLETb4b4b4, Te6edf3titleTb4b4b4)
Te6edf3mActivityTff7b72.Td2a8ffstartActivityForResultTb4b4b4(
Te6edf3IntentTff7b72.Td2a8ffcreateChooserTb4b4b4(Te6edf3file_intentTb4b4b4, Te6edf3castTb4b4b4(
Ta5d6ff'Ta5d6ffjava.lang.CharSequenceTa5d6ff'Tb4b4b4,
Te6edf3StringTb4b4b4(Ta5d6ff"Ta5d6ffFileChooserTa5d6ff"Tb4b4b4)
Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tff7b72selfTff7b72.Td2a8ffsave_code
Tb4b4b4)
Tff7b72def Td2a8ff_on_activity_resultTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3request_codeTb4b4b4, Te6edf3result_codeTb4b4b4, Te6edf3dataTb4b4b4)Tb4b4b4:
T8b949e'''
Listener for ``android.app.Activity.onActivityResult()`` assigned
via ``android.activity.bind()``.
.. versionadded:: 1.4.0
'''
T8b949e# bad data
Tff7b72if Te6edf3data Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return
Tff7b72if Te6edf3result_code Tff7b72!= Te6edf3ActivityTff7b72.Td2a8ffRESULT_OKTb4b4b4:
T8b949e# The action had been cancelled.
Tff7b72return
Tff7b72if Te6edf3request_code Tff7b72== Tff7b72selfTff7b72.Td2a8ffselect_codeTb4b4b4:
Te6edf3selection Tff7b72= Tb4b4b4[Tb4b4b4]
T8b949e# Process multiple URI if multiple files selected
Tff7b72tryTb4b4b4:
Tff7b72for Te6edf3count Tff7b72in Tffa657rangeTb4b4b4(Te6edf3dataTff7b72.Td2a8ffgetClipDataTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffgetItemCountTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3ele Tff7b72= Tff7b72selfTff7b72.Td2a8ff_resolve_uriTb4b4b4(
Te6edf3dataTff7b72.Td2a8ffgetClipDataTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffgetItemAtTb4b4b4(Te6edf3countTb4b4b4)Tff7b72.Td2a8ffgetUriTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72or Tb4b4b4[Tb4b4b4]
Te6edf3selectionTff7b72.Td2a8ffappendTb4b4b4(Te6edf3eleTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3selection Tff7b72= Tb4b4b4[Tff7b72selfTff7b72.Td2a8ff_resolve_uriTb4b4b4(Te6edf3dataTff7b72.Td2a8ffgetDataTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, Tb4b4b4]
T8b949e# return value to object
Tff7b72selfTff7b72.Td2a8ffselection Tff7b72= Te6edf3selection
T8b949e# return value via callback
Tff7b72selfTff7b72.Td2a8ff_handle_selectionTb4b4b4(Te6edf3selectionTb4b4b4)
Tff7b72elif Te6edf3request_code Tff7b72== Tff7b72selfTff7b72.Td2a8ffsave_codeTb4b4b4:
Te6edf3uri Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetDataTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3mActivityTff7b72.Td2a8ffgetContentResolverTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffopenFileDescriptorTb4b4b4(
Te6edf3uriTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"
Tb4b4b4) Tff7b72as Te6edf3pfdTb4b4b4:
Tff7b72with Te6edf3FileOutputStreamTb4b4b4(
Te6edf3pfdTff7b72.Td2a8ffgetFileDescriptorTb4b4b4(Tb4b4b4)
Tb4b4b4) Tff7b72as Te6edf3fileOutputStreamTb4b4b4:
T8b949e# return value via callback
Tff7b72selfTff7b72.Td2a8ff_save_callbackTb4b4b4(Te6edf3fileOutputStreamTb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_handle_external_documentsTb4b4b4(Te6edf3uriTb4b4b4)Tb4b4b4:
T8b949e'''
Selection from the system filechooser when using ``Phone``
or ``Internal storage`` or ``SD card`` option from menu.
.. versionadded:: 1.4.0
'''
Te6edf3file_id Tff7b72= Te6edf3DocumentsContractTff7b72.Td2a8ffgetDocumentIdTb4b4b4(Te6edf3uriTb4b4b4)
Te6edf3file_typeTb4b4b4, Te6edf3file_name Tff7b72= Te6edf3file_idTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff'Ta5d6ff:Ta5d6ff'Tb4b4b4)
Te6edf3primary_storage Tff7b72= Te6edf3storagepathTff7b72.Td2a8ffget_external_storage_dirTb4b4b4(Tb4b4b4)
Te6edf3sdcard_storage Tff7b72= Te6edf3storagepathTff7b72.Td2a8ffget_sdcard_dirTb4b4b4(Tb4b4b4)
Te6edf3directory Tff7b72= Te6edf3primary_storage
Tff7b72if Te6edf3file_type Tff7b72== Ta5d6ff"Ta5d6ffprimaryTa5d6ff"Tb4b4b4:
Te6edf3directory Tff7b72= Te6edf3primary_storage
Tff7b72elif Te6edf3file_type Tff7b72== Ta5d6ff"Ta5d6ffhomeTa5d6ff"Tb4b4b4:
Te6edf3directory Tff7b72= Te6edf3joinTb4b4b4(Te6edf3primary_storageTb4b4b4, Te6edf3EnvironmentTff7b72.Td2a8ffDIRECTORY_DOCUMENTSTb4b4b4)
Tff7b72elif Te6edf3sdcard_storage Tff7b72and Te6edf3file_type Tff7b72in Te6edf3sdcard_storageTb4b4b4:
Te6edf3directory Tff7b72= Te6edf3sdcard_storage
Tff7b72return Te6edf3joinTb4b4b4(Te6edf3directoryTb4b4b4, Te6edf3file_nameTb4b4b4)
Tf0883e@staticmethod
Tff7b72def Td2a8ff_handle_media_documentsTb4b4b4(Te6edf3uriTb4b4b4)Tb4b4b4:
T8b949e'''
Selection from the system filechooser when using ``Images``
or ``Videos`` or ``Audio`` option from menu.
.. versionadded:: 1.4.0
'''
Te6edf3file_id Tff7b72= Te6edf3DocumentsContractTff7b72.Td2a8ffgetDocumentIdTb4b4b4(Te6edf3uriTb4b4b4)
Te6edf3file_typeTb4b4b4, Te6edf3file_name Tff7b72= Te6edf3file_idTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff'Ta5d6ff:Ta5d6ff'Tb4b4b4)
Te6edf3selection Tff7b72= Ta5d6ff'Ta5d6ff_id=?Ta5d6ff'
Tff7b72if Te6edf3file_type Tff7b72== Ta5d6ff'Ta5d6ffimageTa5d6ff'Tb4b4b4:
Te6edf3uri Tff7b72= Te6edf3IMediaTff7b72.Td2a8ffEXTERNAL_CONTENT_URI
Tff7b72elif Te6edf3file_type Tff7b72== Ta5d6ff'Ta5d6ffvideoTa5d6ff'Tb4b4b4:
Te6edf3uri Tff7b72= Te6edf3VMediaTff7b72.Td2a8ffEXTERNAL_CONTENT_URI
Tff7b72elif Te6edf3file_type Tff7b72== Ta5d6ff'Ta5d6ffaudioTa5d6ff'Tb4b4b4:
Te6edf3uri Tff7b72= Te6edf3AMediaTff7b72.Td2a8ffEXTERNAL_CONTENT_URI
T8b949e# Other file type was selected (probably in the Documents folder)
Tff7b72elseTb4b4b4:
Te6edf3uri Tff7b72= Te6edf3FilesTff7b72.Td2a8ffgetContentUriTb4b4b4(Ta5d6ff"Ta5d6ffexternalTa5d6ff"Tb4b4b4)
Tff7b72return Te6edf3file_nameTb4b4b4, Te6edf3selectionTb4b4b4, Te6edf3uri
Tf0883e@staticmethod
Tff7b72def Td2a8ff_handle_downloads_documentsTb4b4b4(Te6edf3uriTb4b4b4)Tb4b4b4:
T8b949e'''
Selection from the system filechooser when using ``Downloads``
option from menu. Might not work all the time due to:
1) invalid URI:
jnius.jnius.JavaException:
JVM exception occurred: Unknown URI:
content://downloads/public_downloads/1034
2) missing URI / android permissions
jnius.jnius.JavaException:
JVM exception occurred:
Permission Denial: reading
com.android.providers.downloads.DownloadProvider uri
content://downloads/all_downloads/1034 from pid=2532, uid=10455
requires android.permission.ACCESS_ALL_DOWNLOADS,
or grantUriPermission()
Workaround:
Selecting path from ``Phone`` -> ``Download`` -> ``<file>``
(or ``Internal storage``) manually.
.. versionadded:: 1.4.0
'''
Tff7b72tryTb4b4b4:
Te6edf3download_dir Tff7b72= Te6edf3EnvironmentTff7b72.Td2a8ffgetExternalStoragePublicDirectoryTb4b4b4(
Te6edf3EnvironmentTff7b72.Td2a8ffDIRECTORY_DOWNLOADS
Tb4b4b4)Tff7b72.Td2a8ffgetPathTb4b4b4(Tb4b4b4)
Te6edf3path Tff7b72= Te6edf3AndroidFileChooserTff7b72.Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTff7b72=Te6edf3uriTb4b4b4,
Te6edf3projectionTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ff_display_nameTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3selectionTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3selection_argsTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3sort_orderTff7b72=Tff7b72NoneTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3joinTb4b4b4(Te6edf3download_dirTb4b4b4, Te6edf3pathTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72import T7ee787traceback
Te6edf3tracebackTff7b72.Td2a8ffprint_excTb4b4b4(Tb4b4b4)
T8b949e# known locations, differ between machines
Te6edf3downloads Tff7b72= Tb4b4b4[
Ta5d6ff'Ta5d6ffcontent://downloads/public_downloadsTa5d6ff'Tb4b4b4,
Ta5d6ff'Ta5d6ffcontent://downloads/my_downloadsTa5d6ff'Tb4b4b4,
T8b949e# all_downloads requires separate permission
T8b949e# android.permission.ACCESS_ALL_DOWNLOADS
Ta5d6ff'Ta5d6ffcontent://downloads/all_downloadsTa5d6ff'
Tb4b4b4]
Te6edf3file_id Tff7b72= Te6edf3DocumentsContractTff7b72.Td2a8ffgetDocumentIdTb4b4b4(Te6edf3uriTb4b4b4)
Te6edf3try_uris Tff7b72= Tb4b4b4[
Te6edf3ContentUrisTff7b72.Td2a8ffwithAppendedIdTb4b4b4(
Te6edf3UriTff7b72.Td2a8ffparseTb4b4b4(Te6edf3downTb4b4b4)Tb4b4b4, Te6edf3LongTff7b72.Td2a8ffvalueOfTb4b4b4(Te6edf3file_idTb4b4b4)
Tb4b4b4)
Tff7b72for Te6edf3down Tff7b72in Te6edf3downloads
Tb4b4b4]
T8b949e# try all known Download folder uris
T8b949e# and handle JavaExceptions due to different locations
T8b949e# for content:// downloads or missing permission
Te6edf3path Tff7b72= Tff7b72None
Tff7b72for Te6edf3down Tff7b72in Te6edf3try_urisTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3path Tff7b72= Te6edf3AndroidFileChooserTff7b72.Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTff7b72=Te6edf3downTb4b4b4, Te6edf3projectionTff7b72=Tb4b4b4[Ta5d6ff'Ta5d6ff_dataTa5d6ff'Tb4b4b4]Tb4b4b4,
Te6edf3selectionTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3selection_argsTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3sort_orderTff7b72=Tff7b72None
Tb4b4b4)
Tff7b72except Te6edf3JavaExceptionTb4b4b4:
Tff7b72import T7ee787traceback
Te6edf3tracebackTff7b72.Td2a8ffprint_excTb4b4b4(Tb4b4b4)
T8b949e# we got a path, ignore the rest
Tff7b72if Te6edf3pathTb4b4b4:
Tff7b72break
T8b949e# alternative approach to Downloads by joining
T8b949e# all data items from Activity result
Tff7b72if Tff7b72not Te6edf3pathTb4b4b4:
Tff7b72for Te6edf3down Tff7b72in Te6edf3try_urisTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3path Tff7b72= Te6edf3AndroidFileChooserTff7b72.Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTff7b72=Te6edf3downTb4b4b4, Te6edf3projectionTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3selectionTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3selection_argsTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3sort_orderTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3index_allTff7b72=Tff7b72True
Tb4b4b4)
Tff7b72except Te6edf3JavaExceptionTb4b4b4:
Tff7b72import T7ee787traceback
Te6edf3tracebackTff7b72.Td2a8ffprint_excTb4b4b4(Tb4b4b4)
T8b949e# we got a path, ignore the rest
Tff7b72if Te6edf3pathTb4b4b4:
Tff7b72break
Tff7b72return Te6edf3path
Tff7b72def Td2a8ff_resolve_uriTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3uriTb4b4b4)Tb4b4b4:
T8b949e'''
Resolve URI input from ``android.app.Activity.onActivityResult()``.
.. versionadded:: 1.4.0
'''
Te6edf3uri_authority Tff7b72= Te6edf3uriTff7b72.Td2a8ffgetAuthorityTb4b4b4(Tb4b4b4)
Te6edf3uri_scheme Tff7b72= Te6edf3uriTff7b72.Td2a8ffgetSchemeTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Te6edf3path Tff7b72= Tff7b72None
Te6edf3file_name Tff7b72= Tff7b72None
Te6edf3selection Tff7b72= Tff7b72None
Te6edf3downloads Tff7b72= Tff7b72None
T8b949e# This does not allow file selected from google photos or gallery
T8b949e# or even any other file explorer to work
T8b949e# not a document URI, nothing to convert from
T8b949e# if not DocumentsContract.isDocumentUri(mActivity, uri):
T8b949e# return path
Tff7b72if Te6edf3uri_authority Tff7b72== Ta5d6ff'Ta5d6ffcom.android.externalstorage.documentsTa5d6ff'Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ff_handle_external_documentsTb4b4b4(Te6edf3uriTb4b4b4)
T8b949e# in case a user selects a file from 'Downloads' section
T8b949e# note: this won't be triggered if a user selects a path directly
T8b949e# e.g.: Phone -> Download -> <some file>
Tff7b72elif Te6edf3uri_authority Tff7b72== Ta5d6ff'Ta5d6ffcom.android.providers.downloads.documentsTa5d6ff'Tb4b4b4:
Te6edf3path Tff7b72= Te6edf3downloads Tff7b72= Tff7b72selfTff7b72.Td2a8ff_handle_downloads_documentsTb4b4b4(Te6edf3uriTb4b4b4)
Tff7b72elif Te6edf3uri_authority Tff7b72== Ta5d6ff'Ta5d6ffcom.android.providers.media.documentsTa5d6ff'Tb4b4b4:
Te6edf3file_nameTb4b4b4, Te6edf3selectionTb4b4b4, Te6edf3uri Tff7b72= Tff7b72selfTff7b72.Td2a8ff_handle_media_documentsTb4b4b4(Te6edf3uriTb4b4b4)
T8b949e# parse content:// scheme to path
Tff7b72if Te6edf3uri_scheme Tff7b72== Ta5d6ff'Ta5d6ffcontentTa5d6ff' Tff7b72and Tff7b72not Te6edf3downloadsTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3path Tff7b72= Tff7b72selfTff7b72.Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTff7b72=Te6edf3uriTb4b4b4, Te6edf3projectionTff7b72=Tb4b4b4[Ta5d6ff'Ta5d6ff_dataTa5d6ff'Tb4b4b4]Tb4b4b4, Te6edf3selectionTff7b72=Te6edf3selectionTb4b4b4,
Te6edf3selection_argsTff7b72=Te6edf3file_nameTb4b4b4, Te6edf3sort_orderTff7b72=Tff7b72None
Tb4b4b4)
Tff7b72except Te6edf3JavaExceptionTb4b4b4: T8b949e# handles array error for selection_args
Te6edf3path Tff7b72= Tff7b72selfTff7b72.Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTff7b72=Te6edf3uriTb4b4b4, Te6edf3projectionTff7b72=Tb4b4b4[Ta5d6ff'Ta5d6ff_dataTa5d6ff'Tb4b4b4]Tb4b4b4, Te6edf3selectionTff7b72=Te6edf3selectionTb4b4b4,
Te6edf3selection_argsTff7b72=Tb4b4b4[Te6edf3file_nameTb4b4b4]Tb4b4b4, Te6edf3sort_orderTff7b72=Tff7b72None
Tb4b4b4)
T8b949e# nothing to parse, file:// will return a proper path
Tff7b72elif Te6edf3uri_scheme Tff7b72== Ta5d6ff'Ta5d6fffileTa5d6ff'Tb4b4b4:
Te6edf3path Tff7b72= Te6edf3uriTff7b72.Td2a8ffgetPathTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3path
Tf0883e@staticmethod
Tff7b72def Td2a8ff_parse_contentTb4b4b4(
Te6edf3uriTb4b4b4, Te6edf3projectionTb4b4b4, Te6edf3selectionTb4b4b4, Te6edf3selection_argsTb4b4b4, Te6edf3sort_orderTb4b4b4,
Te6edf3index_allTff7b72=Tff7b72False
Tb4b4b4)Tb4b4b4:
T8b949e'''
Parser for ``content://`` URI returned by some Android resources.
.. versionadded:: 1.4.0
'''
Te6edf3result Tff7b72= Tff7b72None
Te6edf3resolver Tff7b72= Te6edf3mActivityTff7b72.Td2a8ffgetContentResolverTb4b4b4(Tb4b4b4)
Te6edf3read Tff7b72= Te6edf3IntentTff7b72.Td2a8ffFLAG_GRANT_READ_URI_PERMISSION
Te6edf3write Tff7b72= Te6edf3IntentTff7b72.Td2a8ffFLAG_GRANT_READ_URI_PERMISSION
Te6edf3persist Tff7b72= Te6edf3IntentTff7b72.Td2a8ffFLAG_GRANT_READ_URI_PERMISSION
T8b949e# grant permission for our activity
Te6edf3mActivityTff7b72.Td2a8ffgrantUriPermissionTb4b4b4(
Te6edf3mActivityTff7b72.Td2a8ffgetPackageNameTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3uriTb4b4b4,
Te6edf3read Tff7b72| Te6edf3write Tff7b72| Te6edf3persist
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3index_allTb4b4b4:
Te6edf3cursor Tff7b72= Te6edf3resolverTff7b72.Td2a8ffqueryTb4b4b4(
Te6edf3uriTb4b4b4, Te6edf3projectionTb4b4b4, Te6edf3selectionTb4b4b4,
Te6edf3selection_argsTb4b4b4, Te6edf3sort_order
Tb4b4b4)
Te6edf3idx Tff7b72= Te6edf3cursorTff7b72.Td2a8ffgetColumnIndexTb4b4b4(Te6edf3projectionTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3idx Tff7b72!= Tff7b72-T79c0ff1 Tff7b72and Te6edf3cursorTff7b72.Td2a8ffmoveToFirstTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3result Tff7b72= Te6edf3cursorTff7b72.Td2a8ffgetStringTb4b4b4(Te6edf3idxTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3result Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3cursor Tff7b72= Te6edf3resolverTff7b72.Td2a8ffqueryTb4b4b4(
Te6edf3uriTb4b4b4, Te6edf3projectionTb4b4b4, Te6edf3selectionTb4b4b4,
Te6edf3selection_argsTb4b4b4, Te6edf3sort_order
Tb4b4b4)
Tff7b72while Te6edf3cursorTff7b72.Td2a8ffmoveToNextTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3idx Tff7b72in Tffa657rangeTb4b4b4(Te6edf3cursorTff7b72.Td2a8ffgetColumnCountTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3resultTff7b72.Td2a8ffappendTb4b4b4(Te6edf3cursorTff7b72.Td2a8ffgetStringTb4b4b4(Te6edf3idxTb4b4b4)Tb4b4b4)
Te6edf3result Tff7b72= Ta5d6ff'Ta5d6ff/Ta5d6ff'Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3resultTb4b4b4)
Tff7b72return Te6edf3result
Tff7b72def Td2a8ff_file_selection_dialogTb4b4b4(Tff7b72selfTb4b4b4, Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)Tb4b4b4:
Te6edf3mode Tff7b72= Te6edf3kwargsTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff'Ta5d6ffmodeTa5d6ff'Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72if Te6edf3mode Tff7b72== Ta5d6ff'Ta5d6ffopenTa5d6ff'Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_open_fileTb4b4b4(Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)
Tff7b72elif Te6edf3mode Tff7b72== Ta5d6ff'Ta5d6ffsaveTa5d6ff'Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_save_fileTb4b4b4(Tff7b72*Tff7b72*Te6edf3kwargsTb4b4b4)
Tff7b72def Td2a8ffinstanceTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3AndroidFileChooserTb4b4b4(Tb4b4b4)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────